const vTableSelect = {
  //当自定义指令挂载时
  mounted(el, bindings) {
    /**
     * console.log(el, bindings);
     * <table>...</table>
     * {
     *   arg: undefined,
     *   dir: {mounted: ƒ},
     *   instance: Proxy {__v_skip: true},
     *   modifiers: {},
     *   oldValue: undefined,
     *   value: Proxy {tableData: Array(3), selectedData: null, selectedAreaData: Array(0)}
     * }
     */
    //挂载el到vTableSelect对象给外部使用
    vTableSelect.el = el;

    bindEvent(bindings.value);
  }
};

let isMouseOver = false;

function bindEvent(state) {
  const { el } = vTableSelect;
  el.addEventListener('click', handleTDClick.bind(el, state), false);
  el.addEventListener('dblclick', handleTDDoubleClick.bind(el, state), false);
  el.addEventListener('mousedown', handleTDMousedown.bind(el, state), false);
  window.addEventListener('click', handleWindowClick.bind(el, state), false);
}

/**
 * 点击单元格事件
 * @param {*} state
 */
function handleTDClick(state, e) {
  // console.log(state);
  //Proxy {tableData: Array(3), selectedData: null, selectedAreaData: Array(0)}
  if (!isMouseOver) {
    e.stopPropagation();
    restoreSelectedData(state);

    //点击单元格td时
    if (e.target.tagName === 'TD') {
      const { row, column } = getRowAndColumn(e.target);
      const selectedTDData = getTargetData(state.tableData, row, column);
      // console.log(selectedTD);
      //Proxy {id: 1, content: 1, selected: true}
      //当数据里没有选中项数据时
      if (state.selectedData !== selectedTDData) {
        //将当前选中的单元格数据保存至state
        state.selectedData = selectedTDData;
        state.selectedData.selected = true;
      }
    }
  }
}

/**
 * 点击body取消选中事件
 * @param {*} state
 */
function handleWindowClick(state) {
  this.oInput && (state.selectedData.content = this.oInput.value);
  !isMouseOver && restoreSelectedData(state);
}

/**
 * 按下鼠标选择区域事件
 * @param {*} state
 */
function handleTDMousedown(state, e) {
  isMouseOver = false;
  e.stopPropagation();
  restoreSelectedData(state);
  const _handleTDMouseOver = handleTDMouseOver.bind(this, state);

  document.addEventListener('mouseover', _handleTDMouseOver, false);
  document.addEventListener('mouseup', _handleTDMouseUp, false);

  if (e.target.tagName === 'TD') {
    const { row, column } = getRowAndColumn(e.target);

    //记录鼠标按下选中的起始坐标
    // console.log(this); <table>...</table>
    this.startRow = row;
    this.startColumn = column;
  }

  function _handleTDMouseUp() {
    document.removeEventListener('mouseover', _handleTDMouseOver, false);
    document.removeEventListener('mouseup', _handleTDMouseUp, false);
    setTimeout(() => (isMouseOver = false));
  }
}

/**
 * 双击编辑事件
 * @param {*} state
 */
function handleTDDoubleClick(state, e) {
  e.stopPropagation();
  restoreSelectedData(state);
  if (e.target.tagName === 'TD') {
    const { row, column } = getRowAndColumn(e.target);
    state.selectedData = getTargetData(state.tableData, row, column);
    this.oInput = createInput(e.target, state.tableData, row, column);
  }
}

/**
 * 鼠标按住经过单元格触发的事件
 * @param {*} state
 * @param {*} e
 */
function handleTDMouseOver(state, e) {
  isMouseOver = true;
  // console.log(this);
  //<table>...</table>
  e.stopPropagation();
  if (e.target.tagName === 'TD') {
    const { row, column } = getRowAndColumn(e.target);
    //记录鼠标按下选中的结束坐标
    this.endRow = row;
    this.endColumn = column;
    //保存到响应式数据里
    state.selectedAreaData = getSelectedAreaData(
      state.tableData,
      this.startRow,
      this.startColumn,
      this.endRow,
      this.endColumn
    );
  }
}

/**
 * 创建一个输入框
 * @param {*} target 被点击的单元格
 * @param {*} data 响应式数据
 * @param {*} row 行位置
 * @param {*} column 列位置
 * @returns 一个被触发修改包含样式的输入框
 */
function createInput(target, data, row, column) {
  //找到双击的那一项的值
  const { content } = getTargetData(data, row, column);
  const oInput = document.createElement('input');
  oInput.type = 'text';
  oInput.value = content;
  oInput.onfocus = oInput.select; //绑定focus事件
  target.appendChild(oInput);
  oInput.focus();
  oInput.style.cssText = `
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
   text-align: center;
   font-size: 16px;
   box-sizing: border-box;
  `;
  return oInput;
}

/**
 * 根据视图上的data-row和data-column属性来定位该单元格的数据
 * @param {*} target 视图元素的事件源对象
 * @returns 一个新的水平和垂直的单元格定位对象
 */
function getRowAndColumn(target) {
  const { dataset } = target;

  return {
    row: Number(dataset.row),
    column: Number(dataset.column)
  };
}

/**
 * 获取多选的数据
 * @param {*} data 表格响应式初始数据
 * @param {*} startRow 被记录的起始行坐标
 * @param {*} startColumn 被记录的起始列坐标
 * @param {*} endRow 被记录的结束行坐标
 * @param {*} endColumn 被记录的结束列坐标
 * @returns 一个保存了多选单元格数据组成的数组
 */
function getSelectedAreaData(data, startRow, startColumn, endRow, endColumn) {
  const selectedAreaData = [];
  //从上往下拖动时
  if (startRow <= endRow) {
    //行的数值增加表示往下多选
    for (let i = startRow; i <= endRow; i++) {
      _setSelectedAreaData(data[i].data, startColumn, endColumn);
    }
  } else {
    //从下往上拖动时
    //行的数值增加表示往上多选
    for (let i = startRow; i >= endRow; i--) {
      _setSelectedAreaData(data[i].data, startColumn, endColumn);
    }
  }

  /**
   * 保存选中区域的数据
   * @param {*} rowData 行数据
   * @param {*} startColumn 起始列
   * @param {*} endColumn 结束列
   */
  function _setSelectedAreaData(rowData, startColumn, endColumn) {
    //从左往右拖动时
    if (startColumn <= endColumn) {
      //列的数值增加表示往右多选
      for (let j = startColumn; j <= endColumn; j++) {
        _pushColumnData(rowData[j]);
      }
    } else {
      //从右往左拖动时
      //列的数值增加表示往左多选
      for (let j = startColumn; j >= endColumn; j--) {
        _pushColumnData(rowData[j]);
      }
    }
  }

  function _pushColumnData(columnData) {
    columnData.selected = true;
    selectedAreaData.push(columnData);
  }
  return selectedAreaData;
}

/**
 * 专门查找某定位单元格数据的方法
 * @param {*} data 响应式数据里的表格数据
 * @param {*} row 行的索引
 * @param {*} column 列的索引
 * @return 返回一个符合行和列定位的数据
 */
function getTargetData(data, row, column) {
  let target = null;
  data.forEach((_row, _rowIndex) => {
    //匹配该行
    if (row === _rowIndex) {
      _row.data.forEach((_column, _columnIndex) => {
        //匹配该列
        if (column === _columnIndex) {
          target = _column;
        }
      });
    }
  });
  return target;
}

/**
 * 点击当前单元格时使得其他单元格恢复没选中的样式
 * @param {*} state
 */
function restoreSelectedData(state) {
  const { el } = vTableSelect;
  if (state.selectedData) {
    state.selectedData.selected = false;
  }
  if (state.selectedAreaData.length) {
    state.selectedAreaData.forEach((data) => {
      data.selected = false;
    });
    state.selectedAreaData = [];
  }
  //当正在输入修改时
  if (el.oInput) {
    el.oInput.remove();
    el.oInput = null;
  }
}

export default vTableSelect;
